package com.wtwd.device.service.impl;


import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wtwd.device.constant.RespCode;
import com.wtwd.device.dao.GroupInfoMapper;
import com.wtwd.device.model.entity.*;
import com.wtwd.device.model.vo.GetGroupDialVo;
import com.wtwd.device.model.vo.UploadFileVO;
import com.wtwd.device.service.GroupDialService;
import com.wtwd.device.service.GroupInfoService;
import com.wtwd.device.service.GroupLanguageService;
import com.wtwd.device.util.FileUtils;
import com.wtwd.device.utils.MyExcelUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zdl
 * @since 2023-01-03
 */
@Service
public class GroupInfoServiceImpl implements GroupInfoService {

    @Resource
    private GroupInfoMapper groupInfoMapper;

    @Resource
    private GroupDialService groupDialService;

    @Resource
    private GroupLanguageService groupLanguageService;

    @Resource
    private GroupInfoService groupInfoService;

    @Value("${file.http}")
    private String fileHttp;
    @Value("${dial.preview.image}")
    private String previewImg;
    @Value("${dial.file}")
    private String dialFile;
    @Value("${groupName.excel}")
    private String groupNamePath;
    @Value("${file.path}")
    private String filePath;


    @Override
    public IPage<GroupInfo> getGroupInfoByConditionPage(Long customerId, String name, Page<GroupInfo> page) {
        return new LambdaQueryChainWrapper<>(groupInfoMapper)
                .like(StringUtils.isNotBlank(name), GroupInfo::getName, name)
                .eq(customerId != 0, GroupInfo::getCustomerId, customerId)
                .page(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AddGroupInfoCode addGroupInfo(String groupName, Long customerId, String path) {
        AddGroupInfoCode addGroupInfoCode = new AddGroupInfoCode();
        if (StringUtils.isBlank(groupName) || customerId == null) {
            addGroupInfoCode.setRest(false);
            addGroupInfoCode.setRespCode(RespCode.FAILED);
            return addGroupInfoCode;
        }
        if (!authGroupNameExist(customerId, groupName, null, false)) {
            addGroupInfoCode.setRest(false);
            addGroupInfoCode.setRespCode(RespCode.GROPU_NAME_EXIST);
            return addGroupInfoCode;
        }
        GroupInfo groupInfo = new GroupInfo();
        groupInfo.setName(groupName);
        groupInfo.setCustomerId(customerId);
        groupInfo.setSequence(getGroupSequence(customerId));
        groupInfo.setLanguageFile(path);
        int rest = groupInfoMapper.insert(groupInfo);
        if (rest > 0) {
            if (StringUtils.isNotBlank(path)) {
                List<ExcelImportGroupLanguage> excelImportGroupLanguages = readExcelFile(filePath.concat(groupNamePath).concat(path));
                //同步数据库该分组语言的分组包
                if (excelImportGroupLanguages != null && excelImportGroupLanguages.size() > 0) {
                    List<GroupLanguage> groupLanguages = new ArrayList<>();
                    excelImportGroupLanguages.stream().forEach(e -> {
                        GroupLanguage groupLanguage = new GroupLanguage();
                        BeanUtils.copyProperties(e, groupLanguage);
                        groupLanguage.setGroupId(groupInfo.getId());
                        groupLanguages.add(groupLanguage);
                    });
                    groupLanguageService.saveBatch(groupLanguages);
                }
            }
            addGroupInfoCode.setRest(true);
            addGroupInfoCode.setRespCode(RespCode.SUCCESS);
            return addGroupInfoCode;
        } else {
            addGroupInfoCode.setRest(false);
            addGroupInfoCode.setRespCode(RespCode.FAILED);
            return addGroupInfoCode;
        }
    }

    @Override
    public List<ExcelImportGroupLanguage> readExcelFile(String path) {
        MultipartFile file = getMultipartFile(path);
        List<ExcelImportGroupLanguage> excelImportGroupLanguages = new ArrayList<>();
        if (file != null) {
            try {
                excelImportGroupLanguages = MyExcelUtils.importExcel(file, 0, 1, ExcelImportGroupLanguage.class);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return excelImportGroupLanguages;
    }

    public MultipartFile getMultipartFile(String path) {
        File file = new File(path);
        FileItem item = new DiskFileItemFactory().createItem("file"
                , MediaType.MULTIPART_FORM_DATA_VALUE
                , true
                , file.getName());
        try (InputStream input = new FileInputStream(file);
             OutputStream os = item.getOutputStream()) {
            // 流转移
            IOUtils.copy(input, os);
        } catch (Exception e) {
            return null;
        }
        return new CommonsMultipartFile(item);
    }


    @Override
    public boolean authGroupNameExist(Long customerId, String groupName, Integer groupId, boolean isExclude) {
        if (StringUtils.isBlank(groupName) || customerId == null) {
            return false;
        }
        List<GroupInfo> groupInfo = getGroupInfoByCustomerIdAndGroupName(customerId, groupName);
        if (groupInfo != null && groupInfo.size() > 0) {
            if (isExclude) {
                List<GroupInfo> collect = groupInfo.stream().filter(e -> !e.getId().equals(groupId)).collect(Collectors.toList());
                if (collect == null || collect.size() == 0) {
                    return true;
                } else {
                    return false;
                }
            }
            return false;
        }
        return true;
    }

    @Override
    public List<GroupInfo> getGroupInfoByCustomerIdAndGroupName(Long customerId, String groupName) {
        if (StringUtils.isBlank(groupName) || customerId == null) {
            return null;
        }
        return new LambdaQueryChainWrapper<>(groupInfoMapper)
                .eq(customerId != 0, GroupInfo::getCustomerId, customerId)
                .eq(GroupInfo::getName, groupName)
                .list();
    }

    @Override
    public int getGroupSequence(Long customerId) {
        if (customerId == null) {
            return 0;
        }
        List<GroupInfo> groupInfos = getGroupInfoByCustomerId(customerId);
        if (groupInfos != null) {
            Integer sequence = groupInfos.stream().map(GroupInfo::getSequence).max(Integer::compareTo).get();
            return sequence + 1;
        }
        return 1;
    }

    @Override
    public List<GroupInfo> getGroupInfoByCustomerId(Long customerId) {
        if (customerId == null) {
            return null;
        }
        return new LambdaQueryChainWrapper<>(groupInfoMapper)
                .eq(customerId != 0, GroupInfo::getCustomerId, customerId)
                .list();
    }

    @Override
    public Boolean deleteGroup(Integer groupInfoId) {
        if (groupInfoId == null) {
            return false;
        }
        groupLanguageService.deleteByGroupId(groupInfoId);
        groupDialService.deleteByGroupId(groupInfoId);
        return groupInfoMapper.deleteById(groupInfoId) > 0 ? true : false;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean switchingSort(Integer groupId, Integer sequence, Long customerId) {
        GroupInfo groupInfo = getGroupInfoByCustomerIdAndSequence(sequence, customerId);
        if (groupInfo != null) {
            if (groupInfo.getId().equals(groupId)) {//如果交换的是同一组数据,不做操作直接返回
                return true;
            }
            GroupInfo groupInfoOld = groupInfoMapper.selectById(groupId);
            if (groupInfoOld == null) {
                return false;
            }
            updateGroupSequence(groupId, sequence);
            updateGroupSequence(groupInfo.getId(), groupInfoOld.getSequence());
        } else {
            updateGroupSequence(groupId, sequence);
        }
        return true;
    }

    @Override
    public GroupInfo getGroupInfoByCustomerIdAndSequence(Integer sequence, Long customerId) {
        if (sequence == null || customerId == null) {
            return null;
        }
        return new LambdaQueryChainWrapper<>(groupInfoMapper)
                .eq(customerId != 0, GroupInfo::getCustomerId, customerId)
                .eq(GroupInfo::getSequence, sequence)
                .one();
    }

    @Override
    public boolean updateGroupSequence(Integer groupId, Integer sequence) {
        return groupInfoMapper.updateGroupSequence(groupId, sequence) > 0 ? true : false;
    }

    @Override
    public boolean bathAddGroupDial(List<Integer> groupIds, List<GroupDialDto> groupDialDtos) {
        if (groupIds == null || groupIds.size() == 0 || groupDialDtos == null || groupDialDtos.size() == 0) {
            return false;
        }
        List<GroupDial> groupDials = new ArrayList<>();
        for (Integer groupId : groupIds) {
            for (GroupDialDto groupDialDto : groupDialDtos) {
                String watchIds = groupDialDto.getWatchIds();
                String[] split = watchIds.split(GroupDialDto.WATCH_ID_SEPARATE);
                for (int i = 0; i < split.length; i++) {
                    GroupDial groupDial = new GroupDial();
                    groupDial.setDialId(groupDialDto.getDialId());
                    groupDial.setGroupId(groupId);
                    groupDial.setWatchId(split[i]);
                    groupDial.setCreateTime(new Date().getTime());
                    groupDial.setUpdateTime(new Date().getTime());
                    groupDials.add(groupDial);
                }
            }
        }
        return groupDialService.bathInsertOrUpdate(groupDials);
    }

    @Override
    public IPage<GetGroupDialVo> getGroupDialPage(Integer groupId, String dialName, String watchId, Page<GroupInfo> page) {
        if (groupId == null) {
            return null;
        }
        IPage<GetGroupDialVo> groupDialPage = groupInfoMapper.getGroupDialPage(groupId, dialName, watchId, page);
        groupDialPage.getRecords().stream().forEach(e -> {
            String url = fileHttp.concat(previewImg.concat(e.getPreviewImg()));
            e.setPreviewImg(url);
            String fileUrl = fileHttp.concat(dialFile.concat(e.getDialFile()));
            e.setDialFile(fileUrl);
        });
        return groupDialPage;
    }

    @Override
    public List<GroupInfo> getGroupInfoByWatchId(String watchId, String type) {
        List<GroupInfo> groupInfos = groupInfoMapper.getGroupInfoByWatchId(watchId);
        return geTranslationLanguage(groupInfos, type);
    }

    @Override
    public List<GroupInfo> geTranslationLanguage(List<GroupInfo> groupInfos, String type) {
        if (StringUtils.isNotBlank(type) && groupInfos != null && groupInfos.size() > 0) {
            List<Integer> groupIds = groupInfos.stream().map(GroupInfo::getId).collect(Collectors.toList());
            List<GroupLanguage> groupLanguages = groupLanguageService.getLanguageByGroupIdsAndType(groupIds, type);
            if (groupLanguages != null && groupLanguages.size() > 0) {
                groupInfos.stream().forEach(groupInfo -> {
                    for (GroupLanguage groupLanguage : groupLanguages) {
                        if (groupInfo.getId().equals(groupLanguage.getGroupId()) && StringUtils.isNotBlank(groupLanguage.getTranslation())) {
                            groupInfo.setName(groupLanguage.getTranslation());
                        }
                    }
                });
            }
        }
        return groupInfos;
    }

    @Override
    public List<DialManagement> getDialByWatchIdAndGroupIdPage(Integer groupId, String watchId, int currentPage, int pageSize) {
        Integer start = pageSize * currentPage;
        List<DialManagement> dialManagements = groupInfoMapper.getDialByWatchIdAndGroupId(groupId, watchId, start, pageSize);
        if (dialManagements != null && dialManagements.size() > 0) {
            dialManagements.stream().forEach(e -> {
                String url = fileHttp.concat(previewImg.concat(e.getPreviewImg()));
                e.setPreviewImg(url);
                String fileUrl = fileHttp.concat(dialFile.concat(e.getDialFile()));
                e.setDialFile(fileUrl);
            });
        }
        return dialManagements;
    }

    @Override
    public List<GetGroupIdAndDialByGroupIds> getGroupIdAndDialByGroupIds(List<Integer> groupIds, String watchId) {
        if (groupIds == null || groupIds.size() == 0 || StringUtils.isBlank(watchId)) {
            return null;
        }
        List<GetGroupIdAndDialByGroupIds> datas = groupInfoMapper.getGroupIdAndDialByGroupIds(groupIds, watchId);
        datas.stream().forEach(e -> {
            String url = fileHttp.concat(previewImg.concat(e.getPreviewImg()));
            e.setPreviewImg(url);
            String fileUrl = fileHttp.concat(dialFile.concat(e.getDialFile()));
            e.setDialFile(fileUrl);
        });
        return datas;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateGroupName(Integer groupId, String name, String path, long customerId) {
        if (!authGroupNameExist(customerId, name, groupId, true)) {
            return false;
        }
        if (StringUtils.isNotBlank(path)) {
            List<ExcelImportGroupLanguage> excelImportGroupLanguages = readExcelFile(filePath.concat(groupNamePath).concat(path));
            //同步数据库该分组语言的分组包
            if (excelImportGroupLanguages != null && excelImportGroupLanguages.size() > 0) {
                List<GroupLanguage> groupLanguages = new ArrayList<>();
                excelImportGroupLanguages.stream().forEach(e -> {
                    GroupLanguage groupLanguage = new GroupLanguage();
                    BeanUtils.copyProperties(e, groupLanguage);
                    groupLanguage.setGroupId(groupId);
                    groupLanguages.add(groupLanguage);
                });
                groupLanguageService.synchronizationLanguage(groupId, groupLanguages);
            }
        } else {//传空认为删除文件
            groupLanguageService.deleteByGroupId(groupId);
        }
        GroupInfo groupInfo = new GroupInfo();
        groupInfo.setId(groupId);
        groupInfo.setName(name);
        groupInfo.setLanguageFile(path);
        return groupInfoMapper.updateById(groupInfo) > 0 ? true : false;
    }


    @Override
    public UploadFileVO uploadPortrait(MultipartFile file) {
        String path = filePath.concat(groupNamePath);
        File saveFile = new File(path);
        if (!saveFile.exists()) {
            //文件不存在则创建一个
            saveFile.mkdir();
        }
        String originalFilename = file.getOriginalFilename();
        String fileName = UUID.randomUUID().toString().concat(originalFilename);
        String filepath = "";
        try {
            FileUtils.uploadFile(path, fileName, file.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        UploadFileVO uploadFileVO = new UploadFileVO();
        uploadFileVO.setFileUrl(fileName);
        return uploadFileVO;
    }

    @Override
    public boolean synchronizationGroupDial(Integer dialId, List<String> currentWatchIds) {
        if (currentWatchIds == null || currentWatchIds.size() == 0) {
            return false;
        }
        List<GroupDial> groupDials = groupDialService.getGroupDialByDialId(dialId);
        //确认这个表盘id在哪些分组里面
        List<Integer> groupIds = groupDials.stream().map(GroupDial::getGroupId).distinct().collect(Collectors.toList());
        if (groupIds != null && groupIds.size() > 0) {
            //现在存在哪些手表id
            List<String> watchIds = groupDials.stream().map(GroupDial::getWatchId).distinct().collect(Collectors.toList());
            ContrastList contrastList = contrastListGetAddDateAndDeleteDate(watchIds, currentWatchIds);
            List<String> addWatchId = contrastList.getAdds();
            List<String> deleteWatchId = contrastList.getDeletes();
            if (addWatchId != null&&addWatchId.size()>0) {
                ArrayList<GroupDial> addGroupDial = new ArrayList<>();
                for (Integer groupId : groupIds) {
                    for (String watchId : addWatchId) {
                        GroupDial groupDial = new GroupDial();
                        groupDial.setDialId(dialId);
                        groupDial.setWatchId(watchId);
                        groupDial.setGroupId(groupId);
                        addGroupDial.add(groupDial);
                    }
                }
                if (addGroupDial != null && addGroupDial.size() > 0) {
                    groupDialService.saveBatch(addGroupDial);
                }
            }
            if (deleteWatchId != null && deleteWatchId.size() > 0) {
                ArrayList<GroupDial> delGroupDial = new ArrayList<>();
                for (Integer groupId : groupIds) {
                    for (String watchId : deleteWatchId) {
                        GroupDial groupDial = new GroupDial();
                        groupDial.setDialId(dialId);
                        groupDial.setWatchId(watchId);
                        groupDial.setGroupId(groupId);
                        delGroupDial.add(groupDial);
                    }
                }
                if (delGroupDial != null && delGroupDial.size() > 0) {
                    groupDialService.bathDelGroupDial(delGroupDial);
                }
            }
        }
        return false;
    }


    @Override
    public ContrastList contrastListGetAddDateAndDeleteDate(List<String> oldList, List<String> newList) {
        Collection<String> intersection = CollectionUtil.intersection(oldList, newList);
        Collection<String> del = CollectionUtil.disjunction(oldList, intersection);
        Collection<String> add = CollectionUtil.disjunction(newList, intersection);
        List<String> adds = new ArrayList<>();
        List<String> dels = new ArrayList<>();
        del.forEach(e -> dels.add(e));
        add.forEach(e -> adds.add(e));
        ContrastList contrastList = new ContrastList();
        contrastList.setAdds(adds);
        contrastList.setDeletes(dels);
        return contrastList;
    }

    @Override
    public List<GroupInfo> getGroupInfoByDialId(Integer dialId) {
        return groupInfoMapper.getGroupInfoByDialId(dialId);
    }

}
